import type { DragElementConfig } from '../../../../../../lib/drag_handler'
import type {
  AdResultSelectors,
  SearchAdBadgeOptions,
  SearchPageAdBadgeOptions,
  SearchPageTitleCleanupConfig,
  SearchSelectorConfig,
} from '../index'
import type { PageSearchMetaSourceConfig, PageSearchMetaTimeConfig } from './index'
import { StyleModule } from '../../../../../../lib/abstract'
import { DragHandler } from '../../../../../../lib/drag_handler'
import { PageHandler } from '../../../../../../lib/page_handler'
import {
  SOGOU_SEARCH_PAGE_SELECTORS,
  SOGOU_SEARCH_SELECTORS,
  SogouPageType,
} from '../../../../../../lib/page_handler/platform/sogou/types'
import { ToolKit } from '../../../../../../lib/utils/toolkit'
import {
  AppStyleCollections,
  HOSTNAME,
  LOCAL_STORAGE_KEYS,
  logger,
  SUPPORTED_PLATFORMS,
} from '../../../../../../types/constants'
import { SearchStyle } from './index'

export class SogouStyle extends StyleModule {
  readonly name: string = 'SogouStyle'
  private static instance: SogouStyle
  private pageHandler: PageHandler = PageHandler.getInstance()
  private searchStyle: SearchStyle = SearchStyle.getInstance()
  private readonly pageType = this.pageHandler.pages.sogou.pageType
  private readonly selectors: SearchSelectorConfig = this.pageHandler.pages.sogou.getResultSelectors()
  private indexSearchObserver: MutationObserver | null = null

  constructor() {
    super()

    if (HOSTNAME !== SUPPORTED_PLATFORMS.SO_GOU)
      return

    this.searchStyle.executeInit(
      this.selectors.selector,
      [
        SogouPageType.Video,
      ],
      () => {
        this.init()
      },
    )
  }

  static getInstance(): SogouStyle {
    if (!SogouStyle.instance) {
      SogouStyle.instance = new SogouStyle()
    }
    return SogouStyle.instance
  }

  /**
   * 初始化
   */
  init(): void {
    this.initIndexSearchObserver()
    this.initResultMeta()
    this.updateSearchStyle()
    this.updateTitle()
    this.addAdBadge()
    this.initSidebarDrag()
  }

  /**
   * 【搜索主页】初始化观察器
   */
  private initIndexSearchObserver() {
    if (this.pageType !== SogouPageType.IndexSearch)
      return

    // 如果已经存在观察器，先断开
    this.stopObservation()

    // 预先定义节流函数，避免节流函数被重复创建导致节流失效
    const throttledUpdate = ToolKit.func.throttle(() => {
      logger.debug(`[${this.name}] 搜索建议已更新`)
      this.handleIndexSearchSuggestionUpdate()
    }, 100)

    // 遮罩观察器
    this.indexSearchObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
          throttledUpdate()
        }
      })
    })

    const selector = SOGOU_SEARCH_SELECTORS.indexSearch.suggestionContainer
    const target = document.querySelector(selector)

    if (!target) {
      logger.warn(`[${this.name}] [搜索主页] 搜索建议容器未找到`, selector)
      return
    }

    // 监听变化
    this.indexSearchObserver.observe(target, {
      childList: true,
      subtree: true,
    })

    logger.attention(`[${this.name}] 已启用搜索建议观察`)
  }

  /**
   * 停止观察
   */
  stopObservation(): void {
    this.indexSearchObserver?.disconnect()
    this.indexSearchObserver = null
  }

  /**
   * 【搜索主页】处理搜索建议更新
   */
  private handleIndexSearchSuggestionUpdate(): void {
    const keyword = ($(SOGOU_SEARCH_SELECTORS.indexSearch.input).val() || '') as string

    $(SOGOU_SEARCH_SELECTORS.indexSearch.suggestionItem).not(`[${AppStyleCollections.Search.attr.PROCESSED_HIGHLIGHT}="true"]`).each((_, el) => {
      const $element = $(el)

      this.searchStyle.highlightElement($element, [keyword])

      $element.attr(AppStyleCollections.Search.attr.PROCESSED_HIGHLIGHT, 'true')
    })
  }

  /**
   * 初始化搜索样式
   */
  updateSearchStyle(forceUpdate?: boolean): void {
    const supportPages = [
      SogouPageType.Web,
      SogouPageType.Weixin,
      SogouPageType.Zhihu,
      SogouPageType.Video,
      SogouPageType.Medical,
      SogouPageType.Ask,
      SogouPageType.Encyclopedia,
      SogouPageType.News,
      SogouPageType.Knowledge,
    ]

    this.searchStyle.setBaseStyle(this.selectors, { supportPages, forceUpdate })
  }

  addAdBadge(): void {
    const pageType = PageHandler.getCurrentPageType() as SogouPageType
    const pageConfig: SearchPageAdBadgeOptions = {
      [SogouPageType.Web]: {
        config: (SOGOU_SEARCH_PAGE_SELECTORS[pageType]?.adResult || {}) as AdResultSelectors,
      },
      [SogouPageType.Ask]: {
        config: (SOGOU_SEARCH_PAGE_SELECTORS[pageType]?.adResult || {}) as AdResultSelectors,
      },
      [SogouPageType.Encyclopedia]: {
        config: (SOGOU_SEARCH_PAGE_SELECTORS[pageType]?.adResult || {}) as AdResultSelectors,
      },
      [SogouPageType.Knowledge]: {
        config: (SOGOU_SEARCH_PAGE_SELECTORS[pageType]?.adResult || {}) as AdResultSelectors,
      },
    }

    const currentConfig = (pageConfig[pageType] || {}) as SearchAdBadgeOptions

    if (Object.keys(currentConfig).length === 0) {
      return
    }

    const { onPrepare, config = {} as AdResultSelectors } = currentConfig

    this.searchStyle.addAdBadge({ onPrepare, config })
  }

  /**
   * 初始化结果元数据
   */
  initResultMeta(): void {
    const baseSourceConfig = {
      selector: '.citeurl span:not(.cite-date):first-child',
      container: '.citeurl',
    }

    const webSourceConfig = {
      base: {
        selector: '.citeurl span:not(.cite-date):first-child, [class^=movie-struct__source] span:not([class]), [class^=component-tag] span:not([class*=publishTime]), .fb cite[id^=cacheresult_info], div[class*=link__saLink]:contains(搜狗汉语), div[class*=one-result__footerText], .p-cite span:not([class])',
        container: '.citeurl, [class^=movie-struct__source], [class^=component-tag], .fb, div[class*=link__saLink]:contains(搜狗汉语), div[class*=one-result__footerText], .p-cite',
      },
    }

    const sourceConfig: PageSearchMetaSourceConfig = {
      [SogouPageType.Web]: webSourceConfig,
      [SogouPageType.Weixin]: {
        base: {
          selector: '.s-p .all-time-y2',
          container: '.s-p',
        },
      },
      [SogouPageType.Zhihu]: {
        base: {
          ...baseSourceConfig,
          onlyHide: true,
        },
      },
      [SogouPageType.Video]: {
        base: {
          selector: '.sort_lst_txt .sort_lst_txt_rgt',
          container: '.sort_lst_txt',
          enableIcon: true,
        },
      },
      [SogouPageType.Medical]: {
        base: {
          ...baseSourceConfig,
        },
      },
      [SogouPageType.Ask]: {
        base: {
          ...baseSourceConfig,
          onlyHide: true,
        },
      },
      [SogouPageType.Encyclopedia]: {
        base: {
          selector: '.citeurl span:not(.cite-date):first-child, .title-newblue .more-box span',
          container: '.citeurl, .title-newblue .more-box',
          onlyHide: true,
        },
      },
      [SogouPageType.News]: {
        base: {
          selector: '.news-from span:first-child, [class^=component-tag] span:not([class*=publishTime])',
          container: '.news-from, [class^=component-tag]',
        },
      },
      [SogouPageType.Knowledge]: {
        base: {
          selector: '.citeurl span:not(.cite-date):first-child, .title-newblue .more-box span, .fb cite',
          container: '.citeurl, .title-newblue .more-box, .fb cite',
        },
      },
    }

    const baseTimeConfig = {
      selector: '.citeurl .cite-date',
    }

    const timeConfig: PageSearchMetaTimeConfig = {
      [SogouPageType.Web]: {
        selector: '.citeurl .cite-date, [class^=movie-struct__source] span[class], [class^=component-tag] span[class*=publishTime], .fb cite[id^=cacheresult_info], .p-cite .pc-ad-date',
        cleanFunc: (text: string) => text
          .replace(/^-/, '')
          .replace(/&nbsp;/g, '')
          .trim(),
      },
      [SogouPageType.Weixin]: {
        selector: '.s-p .s2',
      },
      [SogouPageType.Zhihu]: baseTimeConfig,
      [SogouPageType.Video]: {
        selector: '.sort_lst_txt',
        excludeTags: ['span'],
      },
      [SogouPageType.Medical]: baseTimeConfig,
      [SogouPageType.Ask]: baseTimeConfig,
      [SogouPageType.Encyclopedia]: baseTimeConfig,
      [SogouPageType.News]: {
        selector: '.news-from span:last-child, [class^=component-tag] span[class*=publishTime]',
      },
      [SogouPageType.Knowledge]: {
        selector: '.citeurl .cite-date, .best-answer .zs-time span:first-child',
      },
    }

    this.searchStyle.createResultMeta(
      this.selectors.selector,
      {
        leftConfig: sourceConfig,
        rightConfig: timeConfig,
      },
    )
  }

  /**
   * 更新标题
   */
  updateTitle(): void {
    const supportPages = [
      SogouPageType.Zhihu,
      SogouPageType.Ask,
      SogouPageType.Encyclopedia,
    ]

    if (!supportPages.includes(this.pageType as SogouPageType))
      return

    const config: SearchPageTitleCleanupConfig = {
      [SogouPageType.Zhihu]: {
        platformName: '知乎',
      },
      [SogouPageType.Ask]: {
        platformName: '搜狗问问',
      },
      [SogouPageType.Encyclopedia]: {
        platformName: '搜狗百科',
      },
    }

    this.searchStyle.updateTitle({
      config,
      container: this.selectors.selector,
      titleSelector: 'h3 a',
      highlightKeywords: ToolKit.browser.url.getUrlParams('query'),
    })
  }

  private initSidebarDrag(): void {
    const supportPages = [
      SogouPageType.Web,
    ]

    if (!supportPages.includes(this.pageType as SogouPageType))
      return

    const asideConfig = (SOGOU_SEARCH_PAGE_SELECTORS[this.pageType as SogouPageType]?.rightAside || {}) as DragElementConfig

    const dragHandler = new DragHandler({
      elementConfig: asideConfig,
      storageKey: `${LOCAL_STORAGE_KEYS.Sidebar}-${this.pageType}`,
    })
    dragHandler.init()
  }
}
